using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;

[TestClass]
public class OrderServiceTests
{
    private OrderService _orderService;

    [TestInitialize]
    public void Initialize()
    {
        _orderService = new OrderService();
    }

    [TestMethod]
    public void AddOrder_ShouldAddOrder()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };

        // Act
        _orderService.AddOrder(order);

        // Assert
        Assert.IsTrue(_orderService.QueryOrders(o => o.OrderId == "001").Any());
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void AddOrder_ShouldThrowExceptionOnDuplicateOrder()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };

        // Act
        _orderService.AddOrder(order);
        _orderService.AddOrder(order);
    }

    [TestMethod]
    public void DeleteOrder_ShouldDeleteOrder()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order);

        // Act
        _orderService.DeleteOrder("001");

        // Assert
        Assert.IsFalse(_orderService.QueryOrders(o => o.OrderId == "001").Any());
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void DeleteOrder_ShouldThrowExceptionOnNonexistentOrder()
    {
        // Act
        _orderService.DeleteOrder("999");
    }

    [TestMethod]
    public void UpdateOrder_ShouldUpdateOrder()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order);

        var updatedProduct = new Product { Name = "商品B", Price = 200 };
        var updatedOrderDetail = new OrderDetail { Product = updatedProduct, Quantity = 1 };
        var updatedOrder = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail, updatedOrderDetail } };

        // Act
        _orderService.UpdateOrder("001", updatedOrder);

        // Assert
        var updatedOrders = _orderService.QueryOrders(o => o.OrderId == "001");
        Assert.IsTrue(updatedOrders.Any());
        Assert.AreEqual(updatedOrder.TotalAmount, updatedOrders.First().TotalAmount);
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void UpdateOrder_ShouldThrowExceptionOnNonexistentOrder()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };

        // Act
        _orderService.UpdateOrder("999", order);
    }

    [TestMethod]
    public void QueryOrders_ShouldReturnOrdersByPredicate()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order);

        // Act
        var orders = _orderService.QueryOrders(o => o.Customer.Name == "张三");

        // Assert
        Assert.AreEqual(1, orders.Count);
        Assert.AreEqual("001", orders.First().OrderId);
    }

    [TestMethod]
    public void SortOrders_ShouldSortOrdersByOrderId()
    {
        // Arrange
        var customer1 = new Customer { Name = "张三" };
        var customer2 = new Customer { Name = "李四" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order1 = new Order { OrderId = "002", Customer = customer1, Details = new List<OrderDetail> { orderDetail } };
        var order2 = new Order { OrderId = "001", Customer = customer2, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order1);
        _orderService.AddOrder(order2);

        // Act
        var orders = _orderService.SortOrders(sortBy: "OrderId");

        // Assert
        Assert.AreEqual("001", orders.First().OrderId);
        Assert.AreEqual("002", orders.Last().OrderId);
    }

    [TestMethod]
    public void SortOrders_ShouldSortOrdersByTotalAmount()
    {
        // Arrange
        var customer1 = new Customer { Name = "张三" };
        var customer2 = new Customer { Name = "李四" };
        var product1 = new Product { Name = "商品A", Price = 100 };
        var product2 = new Product { Name = "商品B", Price = 200 };
        var orderDetail1 = new OrderDetail { Product = product1, Quantity = 2 };
        var orderDetail2 = new OrderDetail { Product = product2, Quantity = 1 };
        var order1 = new Order { OrderId = "002", Customer = customer1, Details = new List<OrderDetail> { orderDetail1 } };
        var order2 = new Order { OrderId = "001", Customer = customer2, Details = new List<OrderDetail> { orderDetail2 } };
        _orderService.AddOrder(order1);
        _orderService.AddOrder(order2);

        // Act
        var orders = _orderService.SortOrders(sortBy: "TotalAmount");

        // Assert
        Assert.AreEqual("002", orders.First().OrderId);
        Assert.AreEqual("001", orders.Last().OrderId);
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void SortOrders_ShouldThrowExceptionOnInvalidSortField()
    {
        // Act
        _orderService.SortOrders(sortBy: "InvalidField");
    }

    [TestMethod]
    public void AddOrderDetail_ShouldAddOrderDetail()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order);

        var additionalProduct = new Product { Name = "商品B", Price = 200 };
        var additionalOrderDetail = new OrderDetail { Product = additionalProduct, Quantity = 1 };

        // Act
        _orderService.AddOrderDetail("001", additionalOrderDetail);

        // Assert
        var updatedOrder = _orderService.QueryOrders(o => o.OrderId == "001").First();
        Assert.AreEqual(2, updatedOrder.Details.Count);
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void AddOrderDetail_ShouldThrowExceptionOnNonexistentOrder()
    {
        // Arrange
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };

        // Act
        _orderService.AddOrderDetail("999", orderDetail);
    }

    [TestMethod]
    [ExpectedException(typeof(Exception))]
    public void AddOrderDetail_ShouldThrowExceptionOnDuplicateOrderDetail()
    {
        // Arrange
        var customer = new Customer { Name = "张三" };
        var product = new Product { Name = "商品A", Price = 100 };
        var orderDetail = new OrderDetail { Product = product, Quantity = 2 };
        var order = new Order { OrderId = "001", Customer = customer, Details = new List<OrderDetail> { orderDetail } };
        _orderService.AddOrder(order);

        // Act
        _orderService.AddOrderDetail("001", orderDetail);
    }
}
